﻿using System;
using System.ComponentModel;
using Loki.Core.Test.Events;
using Loki.IoC;
using Loki.IoC.Registration;
using Loki.UI;
using Loki.Utils;
using NUnit.Framework;

namespace Loki.Core.Test
{
    [TestFixture]
    public class LokiServicesTest : AssertionHelper
    {
        [Test]
        public void CommandPresenceTest()
        {
            Expect(
                Toolkit.Commands,
                Is.Not.Null
                );
        }

        [Test]
        public void LoggerPresenceTest()
        {
            Expect(
                Toolkit.Logger,
                Is.Not.Null
                );
        }

        [Test]
        public void TestLazy()
        {
            IObjectContext context = Toolkit.IoC.CreateContext("testContext");
            context.Register(Element.For<INotifyPropertyChanged>().ImplementedBy<DummyObserved>().Lifestyle.NoTracking);

            var lazy = new LazyResolver<INotifyPropertyChanged>(context);

            Expect(lazy.IsValueCreated, Is.False);

            Expect(lazy.Value, Is.InstanceOf<DummyObserved>());
        }

        [Test]
        public void IgnoreTest()
        {
            using (IObjectContext L_Context = Toolkit.IoC.CreateContext("Test"))
            {
                L_Context.Register(Element.For<ISupportInitialize>().ImplementedBy<DummyComponent1>());

                L_Context.Register(Element.For<DummyRoot>().Properties(
                    Property<DummyRoot>.ForKey(x => x.Component2).Ignore()));

                DummyRoot L_Root = L_Context.Get<DummyRoot>();

                Expect(L_Root.Component, Is.InstanceOf<DummyComponent1>());
                Expect(L_Root.Component2, Is.Null);
            }
        }

        [Test]
        public void NoTrackingTest()
        {
            IObjectContext context = Toolkit.IoC.CreateContext("testContext");
            context.Register(Element.For<INotifyPropertyChanged>().ImplementedBy<DummyObserved>().Lifestyle.NoTracking);

            WeakReference L_ObjectReference = null;
            new Action(() =>
            {
                object L_Object = context.Get<INotifyPropertyChanged>();
                Expect(L_Object, Is.Not.Null);
                Expect(L_Object.GetType(), Is.EqualTo(typeof(DummyObserved)));
                L_ObjectReference = new WeakReference(L_Object);
            })();

            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Assert.IsNull(L_ObjectReference.Target);
        }

        [Test]
        public void ObjectModelTest()
        {
            IObjectContext context = Toolkit.IoC.CreateContext("testContext");
            context.Register(Element.For<INotifyPropertyChanged>().ImplementedBy<DummyObserved>().Lifestyle.NoTracking);

            object L_Object = context.Get<INotifyPropertyChanged>();
            Expect(L_Object, Is.Not.Null);

            Expect(L_Object.GetType(), Is.EqualTo(typeof(DummyObserved)));
        }

        [Test]
        public void OverrideDoubleNameTest()
        {
            using (IObjectContext L_Context = Toolkit.IoC.CreateContext("Test"))
            {
                L_Context.Register(Element.For<ITaskComponent>().ImplementedBy<DummyTask>().Named("Test"));
                L_Context.Register(Element.For<ISupportInitialize>().Named("Test").ImplementedBy<DummyComponent2>());

                ITaskComponent L_Engine = L_Context.Get<ITaskComponent>("Test");
                ISupportInitialize L_Init = L_Context.Get<ISupportInitialize>("Test");

                Expect(L_Engine, Is.Not.Null);
                Expect(L_Init, Is.Not.Null);
            }
        }

        [Test]
        public void OverrideTest()
        {
            using (IObjectContext L_Context = Toolkit.IoC.CreateContext("Test"))
            {
                L_Context.Register(Element.For<ISupportInitialize>().ImplementedBy<DummyComponent1>());
                L_Context.Register(Element.For<ISupportInitialize>().Named("Test").ImplementedBy<DummyComponent2>());

                L_Context.Register(Element.For<DummyRoot>().Overrides(Loki.IoC.Registration.Property<DummyRoot>.ForKey(x => x.Component).Value("Test")));

                DummyRoot L_Root = L_Context.Get<DummyRoot>();
                Expect(L_Root.Component, Is.InstanceOf<DummyComponent2>());
            }
        }

        [Test]
        public void RedefinitionTest()
        {
            Toolkit.Context.Register(Element.For<ITaskComponent>().ImplementedBy<DummyTask>());
            Expect(Toolkit.ErrorManager, Is.Not.Null);
            Expect(Toolkit.Events, Is.Not.Null);
            Expect(Toolkit.Logger, Is.Not.Null);
            Expect(Toolkit.Tasks as DummyTask, Is.Not.Null);
            Expect(Toolkit.IoC, Is.Not.Null);

            Expect(
                Toolkit.Commands,
                Is.Not.Null
                );
        }

        [SetUp]
        public void SetUp()
        {
            Toolkit.Reset();
        }

        [Test]
        public void SingletonTest()
        {
            var L_Service1 = Toolkit.Logger;
            var L_Service2 = Toolkit.Logger;
            Expect(L_Service1 == L_Service2, Is.True);
        }

        [Test]
        public void ViewModelCleanUpTest()
        {
            Toolkit.IoC.DefaultContext.Register(Element.For<IScreen>().ImplementedBy<TestViewModel>().Lifestyle.NoTracking);

            WeakReference L_Reference = null;
            new Action(() =>
            {
                IScreen VW = Toolkit.IoC.DefaultContext.Get<IScreen>();
                L_Reference = new WeakReference(VW);
            })();

            Expect(L_Reference.Target, Is.Not.Null);
            //((IScreen)L_Reference.Target).DoCleanup();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();

            Expect(L_Reference.Target, Is.Null);
        }
    }
}